﻿
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;

namespace Red.Controls.Shell
{
    /// <summary>
    /// Interaction logic for Stacker.xaml
    /// </summary>
    public partial class StackerControl : UserControl
    {
        public StackerControl()
        {
            InitializeComponent();
        }
    }

    /// <summary>
    /// Container allowing to create labeled list of controls
    /// </summary>
    [ContentProperty( "Content" )]
    public class Stacker : ElementFacade<StackerControl>
    {
        #region Data

        private CategoryBase _selectedCategory;

        #endregion Data

        #region Attached properties

        public static readonly DependencyProperty LabelProperty =
            DependencyProperty.RegisterAttached( "Label", typeof( string ), typeof( Stacker ),
                new PropertyMetadata( null, LabelPropertyChanged ) );

        public static string GetLabel( DependencyObject element )
        {
            return (string)element.GetValue( LabelProperty );
        }

        public static void SetLabel( DependencyObject element, string value )
        {
            element.SetValue( LabelProperty, value );
        }

        #endregion Attached properties

        #region Properties

        public new static readonly DependencyProperty ContentProperty =
            DependencyProperty.Register( "Content", typeof( ObservableCollection<CategoryBase> ), typeof( Stacker ),
                new FrameworkPropertyMetadata( null ) );

        public static readonly DependencyProperty EditorsWidthProperty =
            DependencyProperty.Register( "EditorsWidth", typeof( GridLength ), typeof( Stacker ),
                new FrameworkPropertyMetadata( new GridLength( 100 ) ) );

        public static readonly DependencyProperty EditorsWidthRatioProperty =
            DependencyProperty.Register( "EditorsWidthRatio", typeof( double ), typeof( Stacker ),
                new FrameworkPropertyMetadata( 0.5 ) );

        public new ObservableCollection<CategoryBase> Content
        {
            get { return (ObservableCollection<CategoryBase>)GetValue( ContentProperty ); }
            set { SetValue( ContentProperty, value ); }
        }

        /// <summary>
        ///     Width of editors in contained categories
        /// </summary>
        public GridLength EditorsWidth
        {
            get { return (GridLength)GetValue( EditorsWidthProperty ); }
            set { SetValue( EditorsWidthProperty, value ); }
        }

        public double EditorsWidthRatio
        {
            get { return (double)GetValue( EditorsWidthRatioProperty ); }
            set { SetValue( EditorsWidthRatioProperty, value ); }
        }

        /// <summary>
        ///     Item that is currently selected
        /// </summary>
        public object SelectedItem
        {
            get { return _selectedCategory?.SelectedItem; }
        }

        #endregion Properties

        #region C-tor

        public Stacker()
        {
            Content = new ObservableCollection<CategoryBase>(); // WARNING: This CANNOT be put as a property default value
            Content.CollectionChanged += Content_CollectionChanged;
            Loaded += Stacker_Loaded;
            SizeChanged += Stacker_SizeChanged;
        }

        #endregion C-tor

        #region Internal methods

        // Ensures, that only one category at the time has a selected item
        internal void SynchronizeSelection( CategoryBase category )
        {
            if ( _selectedCategory == category || category.SelectedItem == null )
                return; // nothing to sync

            if ( _selectedCategory != null )
                _selectedCategory.SelectedItem = null; // de-select from currently selected

            _selectedCategory = category;
        }
        
        #endregion Internal methods

        #region Event handlers

        void Stacker_Loaded( object sender, RoutedEventArgs e )
        {
            EditorsWidth = new GridLength( ActualWidth * EditorsWidthRatio );
        }

        private void Stacker_SizeChanged( object sender, SizeChangedEventArgs e )
        {
            // resize editors proportionally
            if ( e.NewSize.Width != e.PreviousSize.Width && e.PreviousSize.Width != 0.0 )
            {
                EditorsWidthRatio = EditorsWidth.Value / e.PreviousSize.Width;
                EditorsWidth = new GridLength( e.NewSize.Width * EditorsWidthRatio );
            }
        }

        private static void LabelPropertyChanged( DependencyObject obj, DependencyPropertyChangedEventArgs e )
        {
            FrameworkElement element = obj as FrameworkElement;
            if ( element == null )
                throw new ArgumentException( "Invalid object type" );
        }

        private void Content_CollectionChanged( object sender, NotifyCollectionChangedEventArgs e )
        {
            switch ( e.Action )
            {
                case NotifyCollectionChangedAction.Add:

                    foreach ( var obj in e.NewItems )
                        ( (CategoryBase)obj ).IsExpanded = true;

                    break;
            }
        }

        #endregion

    }
}
